395 至少有 K 个重复字符的最长子串
给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
如果不存在这样的子字符串,则返回 0。
示例 1:
** 输入:**s = "aaabb", k = 3 ** 输出:**3 ** 解释:** 最长子串为 "aaa" ,其中 'a' 重复了 3 次。
示例 2:
** 输入:**s = "ababbc", k = 2 ** 输出:**5 ** 解释:** 最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
递归函数的含义:函数入参 s 是表示源字符串;k 是限制条件,即子字符串中每个字符最少出现的次数;函数返回结果是满足题意的最长子字符串长度。 递归的终止条件(base case):如果字符串 s 的长度少于 k,那么一定不存在满足题意的子字符串,返回 0; 怎样分解子问题:如果一个字符 c 在 s 中出现的次数少于 k 次,那么 s 中所有的包含 c 的子字符串都不能满足题意,因此应该在 s 的所有不包含 c 的子字符串中去寻找结果
js
/**
* @param {string} s
* @param {number} k
* @return {number}
*/
var longestSubstring = function (s, k) {
// base case 如果源字符串比限制长度k还要小,肯定即便s中所有字符都是同一个也不满足条件
if (s.length < k) return 0;
// 源字符串中每个字符出现的次数存入map中
let counter = new Map();
for (let i = 0; i < s.length; i++) {
counter.set(s[i], (counter.get(s[i]) || 0) + 1);
}
for (let c of counter.keys()) {
// 字符 c 在 s 中出现的次数少于 k 次,s中所有包含c的子字符串都不能满足
if (counter.get(c) < k) {
// 应该在s中所有不包含c的子字符串中查找
let count = 0;
for (let t of s.split(c)) {
count = Math.max(count, longestSubstring(t, k));
}
return count;
}
}
return s.length;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26